package com.keeping.aiimagery.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.keeping.aiimagery.entity.ChatRecord;
import com.keeping.aiimagery.entity.MsgVO;
import com.keeping.aiimagery.entity.enums.MsgType;
import com.keeping.aiimagery.service.ChatRecordService;
import com.keeping.aiimagery.service.UserService;
import com.keeping.aiimagery.service.impl.ChatRecordServiceImpl;
import com.keeping.aiimagery.service.impl.UserServiceImpl;
import com.keeping.aiimagery.util.RedisService;
import com.keeping.aiimagery.util.StrUtils;
import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.springframework.context.ApplicationContext;

import javax.websocket.Session;
import java.util.List;
import java.util.Objects;

/**
 * 描述：OpenAI流式输出Socket接收
 *
 * @author Ranger
 * @date 2023-03-23
 */
@Slf4j
public class OpenAIWebSocketEventSourceListener extends EventSourceListener {

    private static ApplicationContext applicationContext;
    private Session session;

    private String userId;
    
    private String roomId;

    private UserService userService;
    
    private ChatRecordService chatRecordService;
    
    private RedisService redisService;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        OpenAIWebSocketEventSourceListener.applicationContext = applicationContext;
    }

    public OpenAIWebSocketEventSourceListener(Session session) {
        this.session = session;
    }

    public OpenAIWebSocketEventSourceListener(Session session, String userId, String roomId) {
        this.session = session;
        this.userId = userId;
        this.roomId = roomId;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onOpen(EventSource eventSource, Response response) {
        log.info("OpenAI建立sse连接...");
    }

    /**
     * {@inheritDoc}
     */
    @SneakyThrows
    @Override
    public void onEvent(EventSource eventSource, String id, String type, String data) {
        log.info("OpenAI返回数据：{}", data);
        redisService = applicationContext.getBean(RedisService.class);

        ObjectMapper mapper = new ObjectMapper();
        if (data.equals("[DONE]")) {
            log.info("OpenAI返回数据结束了");
            //扣除用户使用次数
            userService = applicationContext.getBean(UserServiceImpl.class);
            //TODO 扣除需要的次数积分等数据
//            userService.modifyUserRemainingTimes(Long.valueOf(userId));

            //保存AI聊天记录
            List<Object> objects = redisService.lGet(roomId, 0L, -1L);
            chatRecordService = applicationContext.getBean(ChatRecordServiceImpl.class);
            ChatRecord build = ChatRecord.builder().message(StrUtils.listToString(objects)).msgType(MsgType.AI).roomId(Long.valueOf(roomId)).build();
            build.created(Long.valueOf(userId));
            chatRecordService.save(build);
            
            String delta = mapper.writeValueAsString(MsgVO.builder().content("").isEnd(true).roomId(roomId).uid(userId).build());
            session.getBasicRemote().sendText(delta);
            //清除缓存
            redisService.del(roomId);
            return;
        }
        ChatCompletionResponse completionResponse = mapper.readValue(data, ChatCompletionResponse.class); // 读取Json
        String content = completionResponse.getChoices().get(0).getDelta().getContent();
        if(content != null){
            MsgVO build = MsgVO.builder().content(content).isEnd(false).roomId(roomId).uid(userId).build();
            redisService.lSet(roomId,content);
            String delta = mapper.writeValueAsString(build);
            session.getBasicRemote().sendText(delta);
        }
    }


    @Override
    public void onClosed(EventSource eventSource) {
        log.info("OpenAI关闭sse连接...");
    }


    @SneakyThrows
    @Override
    public void onFailure(EventSource eventSource, Throwable t, Response response) {
        if (Objects.isNull(response)) {
            return;
        }
        ResponseBody body = response.body();
        if (Objects.nonNull(body)) {
            log.error("OpenAI  sse连接异常data：{}，异常：{}", body.string(), t);
        } else {
            log.error("OpenAI  sse连接异常data：{}，异常：{}", response, t);
        }
        eventSource.cancel();
    }
}
